/*
 * GArchivedStandings.java
 * Created on 30 janv. 08
 *
 * Glacéo Internet Platform
 * http://sourceforge.net/projects/chm/
 *
 * Copyright (c) 2005-2008, Jens and Jan Janke (VirtualHockey Project)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.hockeo.vhbase.data.dao.standings;


import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Locale;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import com.hockeo.vhbase.data.dao.GAbstractDao;
import com.hockeo.vhbase.data.dao.IGEntity;
import com.hockeo.vhbase.data.dao.club.GClub;
import com.hockeo.vhbase.data.dao.contest.GRoundRobinContestElement;
import com.hockeo.vhbase.data.dao.season.GSeason;
import com.hockeo.vhbase.data.helper.GArchivedStandingsType;
import com.hockeo.vhbase.data.helper.GMatchResult;
import com.hockeo.vhbase.data.helper.GStandingsRankType;
import com.hockeo.vhbase.data.helper.GStandingsType;

/**
 * Represents an archived standings record (i.e. a standings record that has been archived
 * or updated at the end of a season).
 *
 * @version $Id$
 * @author jjanke
 */
@Entity
@Table( name = "a_standings" )
public class GArchivedStandings extends GAbstractDao
{
  @Id
  @Column( name = "id" )
  @GeneratedValue( strategy = GenerationType.AUTO )
  private int                       d_nId;

  @Enumerated( EnumType.STRING )
  @Column( name = "archive_type" )
  private GArchivedStandingsType    d_archiveType;

  @Enumerated( EnumType.STRING )
  @Column( name = "type" )
  private GStandingsType            d_type;

  @ManyToOne( fetch = FetchType.LAZY )
  @JoinColumn( name = "season_id" )
  private GSeason                   d_season;

  @ManyToOne( fetch = FetchType.LAZY )
  @JoinColumn( name = "club_id" )
  private GClub                     d_club;

  @ManyToOne( fetch = FetchType.LAZY )
  @JoinColumn( name = "contest_element_id" )
  private GRoundRobinContestElement d_contestElement;

  @Column( name = "num_seasons" )
  private int                       d_nNumSeasons         = 1;

  @Column( name = "rank" )
  private int                       d_nRank               = 1;

  @Enumerated( EnumType.STRING )
  @Column( name = "rank_type" )
  private GStandingsRankType        d_rankType            = GStandingsRankType.MIDFIELD;

  @Column( name = "matches" )
  private int                       d_nNumMatches         = 0;

  @Column( name = "points" )
  private int                       d_nNumPoints          = 0;

  @Column( name = "points_pct" )
  private BigDecimal                d_decPointsPercentage = new BigDecimal( "1.000" );

  @Column( name = "points_avg" )
  private BigDecimal                d_decPointsAverage    = new BigDecimal( "0.000" );

  @Column( name = "wins" )
  private int                       d_nNumWins            = 0;

  @Column( name = "wins_ot" )
  private int                       d_nNumWinsOT          = 0;

  @Column( name = "losses_ot" )
  private int                       d_nNumLossesOT        = 0;

  @Column( name = "losses" )
  private int                       d_nNumLosses          = 0;

  @Column( name = "goals_for" )
  private int                       d_nNumGoalsFor        = 0;

  @Column( name = "goals_against" )
  private int                       d_nNumGoalsAgainst    = 0;

  @Column( name = "goals_diff" )
  private int                       d_nGoalsDiff          = 0;

  /** Default parameterless constructor. */
  protected GArchivedStandings()
  {}

  /**
   * Creates a new standings archive object based on the given season standings object.
   *
   * @param archiveType whether to create season or eternal standings
   * @param season the season for which to archive the standings
   * @param element the contest element for which the standings are archived
   * @param standings the season standings which should be archived
   */
  public GArchivedStandings( GArchivedStandingsType archiveType, GSeason season, GRoundRobinContestElement element, GStandings standings )
  {
    d_season = season;
    d_archiveType = archiveType;
    d_type = standings.getType();
    d_club = standings.getClub();
    d_contestElement = element;
    d_nRank = standings.getRank();
    d_rankType = standings.getRankType();
    d_nNumMatches = standings.getNumMatches();
    d_nNumPoints = standings.getNumPoints();
    d_nNumWins = standings.getNumWins();
    d_nNumWinsOT = standings.getNumWinsOT();
    d_nNumLossesOT = standings.getNumLossesOT();
    d_nNumLosses = standings.getNumLosses();
    d_nNumGoalsFor = standings.getNumGoalsFor();
    d_nNumGoalsAgainst = standings.getNumGoalsAgainst();
    d_nGoalsDiff = d_nNumGoalsFor - d_nNumGoalsAgainst;

    d_decPointsAverage = BigDecimal.valueOf( d_nNumPoints ).divide( BigDecimal.valueOf( d_nNumMatches ), 3,
        RoundingMode.HALF_UP );

    d_decPointsPercentage = BigDecimal.valueOf( d_nNumPoints ).divide(
        BigDecimal.valueOf( d_nNumMatches * GMatchResult.VICTORY.getNumPoints() ), 3, RoundingMode.HALF_UP );

    if ( d_archiveType == GArchivedStandingsType.ETERNAL )
    {
      d_nRank = 1;
      d_rankType = GStandingsRankType.MIDFIELD;
    }
  }

  /**
   * Sets the rank of this standings object.
   *
   * @param nRank the rank to be attributed to these standings
   */
  public void setRank( int nRank )
  {
    d_nRank = nRank;
  }

  public GArchivedStandingsType getArchiveType()
  {
    return d_archiveType;
  }

  /**
   * Returns the season for which these standings are archived if the archive type is
   * {@link GArchivedStandingsType#END_OF_SEASON} or the season when the standings were
   * last updated for eternal standings.
   */
  public GSeason getSeason()
  {
    return d_season;
  }

  public GRoundRobinContestElement getContestElement()
  {
    return d_contestElement;
  }

  public GStandingsType getType()
  {
    return d_type;
  }

  public GClub getClub()
  {
    return d_club;
  }

  public int getNumSeasons()
  {
    return d_nNumSeasons;
  }

  public int getRank()
  {
    return d_nRank;
  }

  public int getNumMatches()
  {
    return d_nNumMatches;
  }

  public int getNumPoints()
  {
    return d_nNumPoints;
  }

  public int getNumWins()
  {
    return d_nNumWins;
  }

  public int getNumWinsOT()
  {
    return d_nNumWinsOT;
  }

  public int getNumLossesOT()
  {
    return d_nNumLossesOT;
  }

  public int getNumLosses()
  {
    return d_nNumLosses;
  }

  public int getNumGoalsFor()
  {
    return d_nNumGoalsFor;
  }

  public int getNumGoalsAgainst()
  {
    return d_nNumGoalsAgainst;
  }

  public int getGoalsDiff()
  {
    return d_nGoalsDiff;
  }

  /**
   * Sets rank type which can e.g. be used to determine the layout of the standings line
   * when rendered as HTML.
   *
   * @param rankType the rank type to be set
   */
  public void setRankType( GStandingsRankType rankType )
  {
    d_rankType = rankType;
  }

  /**
   * Returns the rank type which can e.g. be used to determine the layout of the standings
   * line when rendered as HTML.
   */
  public GStandingsRankType getRankType()
  {
    return d_rankType;
  }

  public String getRankType( Locale locale )
  {
    return translate( "rankType_" + d_rankType.name(), locale );
  }

  /**
   * Returns the avg. number of goals scored per match. If no match has been played so
   * far, 0 is returned.
   */
  public double getGoalsPerMatchAvg()
  {
    return d_nNumMatches > 0 ? d_nNumGoalsFor / (double) d_nNumMatches : 0;
  }

  /**
   * Returns the avg. number of goals scored by the opponents per match. If no match has
   * been played so far, 0 is returned.
   */
  public double getGoalsPerMatchAvgOpponents()
  {
    return d_nNumMatches > 0 ? d_nNumGoalsAgainst / (double) d_nNumMatches : 0;
  }

  /**
   * Returns the avg. number of points per match. If no match has been played so far, 0 is
   * returned.
   */
  public BigDecimal getPointsPerMatchAvg()
  {
    return d_decPointsAverage;
  }

  /**
   * Returns the number of points as a fraction of the maximum possible number of points.
   * The returned value lies between 0 and 1. If no match has been played, 1 is returned.
   */
  public BigDecimal getPointsPercentage()
  {
    return d_decPointsPercentage;
  }

  public int getId()
  {
    return d_nId;
  }

  public Class<? extends IGEntity> getGEntityClass()
  {
    return GArchivedStandings.class;
  }

  /*
   * @see java.lang.Object#equals(java.lang.Object)
   */
  @Override
  public boolean equals( Object obj )
  {
    try
    {
      return d_nId == ( (GArchivedStandings) obj ).getId();
    }
    catch ( Exception ex ) // especially ClassCastException(s) may happen
    {
      return false;
    }
  }

  /*
   * @see java.lang.Object#hashCode()
   */
  @Override
  public int hashCode()
  {
    return d_nId;
  }

  /*
   * @see java.lang.Object#toString()
   */
  @Override
  public String toString()
  {
    return "Archived standings " + d_nId + " for " + d_club.getName() + " (contest element: "
        + d_contestElement.getId() + " / season " + d_season.getName() + ")";
  }
}
